벡터 공간

벡터의 기하학적 의미

길이가 $K$인 벡터(vector) $a$는 $K$차원의 공간에서 원점과 벡터 $a$의 값으로 표시되는 점을 연결한 화살표(arrow)로 간주할 수 있다.

$$ a = \begin{bmatrix}1 \\ 2 \end{bmatrix} $$

In [9]:
a = [1, 2]

plt.annotate('', xy=a, xytext=(0,0), arrowprops=dict(facecolor='black'))

plt.plot(0, 0, 'ro', ms=10)
plt.plot(a[0], a[1], 'ro', ms=10)

plt.text(0.35, 1.15, "$a$", fontdict={"size": 18})

plt.xticks(np.arange(-2, 4))
plt.yticks(np.arange(-1, 4))
plt.xlim(-2.4, 3.4)
plt.ylim(-1.2, 3.2)
plt.show()


벡터의 길이

벡터 $a$ 의 길이를 놈(norm) $\| a \|$ 이라고 하며 다음과 같이 계산할 수 있다.

$$ \| a \| = \sqrt{a^T a } = \sqrt{a_1^2 + \cdots + a_K^2} $$

numpy의 linalg 서브 패키지의 norm 명령으로 벡터의 길이를 계산할 수 있다.


In [10]:
a = np.array([1, 1])
np.linalg.norm(a)


Out[10]:
1.4142135623730951

단위 벡터

길이가 1인 벡터를 단위 벡터(unit vector)라고 한다. 예를 들어 다음과 같은 벡터들은 모두 단위 벡터이다.

$$ a = \begin{bmatrix}1 \\ 0\end{bmatrix} ,\;\; b = \begin{bmatrix}0 \\ 1\end{bmatrix} ,\;\; c = \begin{bmatrix} \dfrac{1}{\sqrt{2}} \\ \dfrac{1}{\sqrt{2}} \end{bmatrix} $$

In [11]:
a = np.array([1, 0])
b = np.array([0, 1])
c = np.array([1/np.sqrt(2), 1/np.sqrt(2)])
np.linalg.norm(a), np.linalg.norm(b), np.linalg.norm(c)


Out[11]:
(1.0, 1.0, 0.99999999999999989)

벡터의 합

벡터와 벡터의 합은 벡터가 된다.

$$ a = \begin{bmatrix}1 \\ 2\end{bmatrix} ,\;\; b = \begin{bmatrix}2 \\ 1\end{bmatrix} \;\;\; \rightarrow \;\;\; c = a + b = \begin{bmatrix}3 \\ 3\end{bmatrix} \;\; $$

In [12]:
a = np.array([1, 2])
b = np.array([2, 1])
c = a + b

plt.annotate('', xy=a, xytext=(0,0), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=b, xytext=(0,0), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=c, xytext=(0,0), arrowprops=dict(facecolor='black'))

plt.plot(0, 0, 'ro', ms=10)
plt.plot(a[0], a[1], 'ro', ms=10)
plt.plot(b[0], b[1], 'ro', ms=10)
plt.plot(c[0], c[1], 'ro', ms=10)
plt.plot([a[0], c[0]], [a[1], c[1]], 'k--')
plt.plot([b[0], c[0]], [b[1], c[1]], 'k--')

plt.text(0.35, 1.15, "$a$", fontdict={"size": 18})
plt.text(1.15, 0.25, "$b$", fontdict={"size": 18})
plt.text(1.25, 1.45, "$c$", fontdict={"size": 18})

plt.xticks(np.arange(-2, 4))
plt.yticks(np.arange(-1, 4))
plt.xlim(-1.4, 4.4)
plt.ylim(-0.6, 3.8)
plt.show()


벡터의 집합 중에서 집합의 원소인 두 벡터의 선형 조합(스칼라 곱의 합)이 그 집합의 원소이면 벡터 공간이라고 한다.

$$ a, b \in \mathbf{R} \;\; \text{ and } \;\; \alpha_1a + \alpha_2b \in \mathbf{R} $$

벡터의 분해

어떤 두 벡터 $a$, $b$의 합이 다른 벡터 $c$가 될 때 $c$가 두 벡터 성분(vector component) $a$, $b$으로 분해(decomposition)된다고 말할 수 있다.

벡터의 직교

두 벡터 $a$와 $b$가 이루는 각이 90도이면 서로 직교(orthogonal)라고 하며 $ a \perp b $로 표시한다.

서로 직교인 두 벡터의 벡터 내적(inner product, dot product)는 0이된다.

$$ a^T b = b^T a = 0 \;\;\;\; \leftrightarrow \;\;\;\; a \perp b $$

예를 들어 다음 두 벡터는 서로 직교한다.

$$ a = \begin{bmatrix}1 \\ 1\end{bmatrix} ,\;\; b = \begin{bmatrix}-1 \\ 1\end{bmatrix} \;\;\;\; \rightarrow \;\;\;\; a^T b = \begin{bmatrix}1 & 1\end{bmatrix} \begin{bmatrix}-1 \\ 1\end{bmatrix} = -1 + 1 = 0 $$

In [13]:
a = np.array([1, 1])
b = np.array([-1, 1])
np.dot(a, b)


Out[13]:
0

투영

벡터 $a$를 다른 벡터 $b$에 직교하는 성분 $a_1$ 와 나머지 성분 $a_2 = a - a_1$로 분해할 수 있다. 이 때 $a_2$는 $b$와 평행하며 이 길이를 벡터 $a$의 벡터 $b$에 대한 투영(projection)이라고 한다.

벡터의 투영은 다음과 같이 내적을 사용하여 구할 수 있다.

$$ a = a_1 + a_2 $$$$ a_1 \perp b \;\; \text{ and } \;\; a_2 = a - a_1 $$

이면

$$ \| a_2 \| = a^T\dfrac{b}{\|b\|} = \dfrac{a^Tb}{\|b\|} = \dfrac{b^Ta}{\|b\|} $$

이다.

또한 두 벡터 사이의 각도 $\theta$는 다음과 같이 구한다.

$$ \cos\theta = \dfrac{\| a_2 \|}{\| a \|} = \dfrac{a^Tb}{\|a\|\|b\|}$$

In [14]:
a = np.array([1, 2])
b = np.array([2, 0])
a2 = np.dot(a, b)/np.linalg.norm(b) * np.array([1, 0])
a1 = a - a2

plt.annotate('', xy=a, xytext=(0,0), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=b, xytext=(0,0), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=a2, xytext=(0,0), arrowprops=dict(facecolor='green'))
plt.annotate('', xy=a1, xytext=(0,0), arrowprops=dict(facecolor='green'))

plt.plot(0, 0, 'ro', ms=10)
plt.plot(a[0], a[1], 'ro', ms=10)
plt.plot(b[0], b[1], 'ro', ms=10)

plt.text(0.35, 1.15, "$a$", fontdict={"size": 18})
plt.text(1.55, 0.15, "$b$", fontdict={"size": 18})
plt.text(-0.2, 1.05, "$a_1$", fontdict={"size": 18})
plt.text(0.50, 0.15, "$a_2$", fontdict={"size": 18})

plt.xticks(np.arange(-2, 4))
plt.yticks(np.arange(-1, 4))
plt.xlim(-1.5, 3.5)
plt.ylim(-0.5, 3)
plt.show()


벡터의 선형 종속과 선형 독립

벡터들의 선형 조합이 0이 되는 모두 0이 아닌 스칼라값들이 존재하면 그 벡터들은 선형 종속(linearly dependent)이라고 한다.

$$ a = \begin{bmatrix}1 \\ 2\end{bmatrix} ,\;\; b = \begin{bmatrix}3 \\ 3\end{bmatrix} \;\; c = \begin{bmatrix}10 \\ 14\end{bmatrix} \;\; $$$$ 2a + b - \frac{1}{2}c = 0 $$

In [15]:
a = np.array([1, 2])
b = np.array([3, 3])
c = np.array([10, 14])
2*a + b - 0.5*c


Out[15]:
array([ 0.,  0.])

벡터들의 선형 조합이 0이 되는 모두 0이 아닌 스칼라값들이 존재하지 않으면 그 벡터들은 선형 독립(linearly independent)이라고 한다.

$$ \alpha_1 a_1 + \cdots + \alpha_K a_K = 0 \;\;\;\; \leftrightarrow \;\;\;\; \alpha_1 = \cdots = \alpha_K = 0 $$

기저 벡터

벡터 공간에 속하는 벡터의 집합이 선형 독립이고 다른 모든 벡터 공간의 벡터들이 그 벡터 집합의 선형 조합으로 나타나면 그 벡터 집합을 벡터 공간의 기저 벡터(basis vector)라고 한다.

예를 들어 다음과 같은 두 벡터는 2차원 벡터 공간의 기저 벡터이다. $$ a = \begin{bmatrix}1 \\ 0\end{bmatrix} ,\;\; b = \begin{bmatrix}0 \\ 1\end{bmatrix} \;\; $$ 또는 $$ a = \begin{bmatrix}1 \\ 1\end{bmatrix} ,\;\; b = \begin{bmatrix}2 \\ 3\end{bmatrix} \;\; $$

다음과 같은 두 벡터는 2차원 벡터 공간의 기저 벡터가 될 수 없다. $$ a = \begin{bmatrix}1 \\ 2\end{bmatrix} ,\;\; b = \begin{bmatrix}2 \\ 4\end{bmatrix} \;\; $$

열 공간

행렬은 열 벡터의 집합으로 볼 수 있다. 이 때 열 벡터들의 조합으로 생성되는 벡터 공간을 열 공간(column space)이라고 한다.

$$ A = \begin{bmatrix} 1 & 5 & 6 \\ 2 & 6 & 8 \\ 7 & 1 & 8 \end{bmatrix} \;\;\;\; \rightarrow \;\;\;\; \alpha_1 \begin{bmatrix} 1 \\ 2 \\ 7 \end{bmatrix} + \alpha_2 \begin{bmatrix} 5 \\ 6 \\ 1 \end{bmatrix} + \alpha_3 \begin{bmatrix} 6 \\ 8 \\ 8 \end{bmatrix} \; \in \; \text{column space} $$

열 랭크

행렬의 열 벡터 중 서로 독립인 열 벡터의 최대 갯수를 열 랭크(column rank) 혹은 랭크(rank)라고 한다.

예를 들어 다음 행렬의 랭크는 2이다.

$$ A = \begin{bmatrix} 1 & 5 & 6 \\ 2 & 6 & 8 \\ 3 & 11 & 14 \end{bmatrix} $$

numpy의 linalg 서브 패키지의 matrix_rank 명령으로 랭크를 계산할 수 있다.


In [16]:
A = np.array([[1, 5, 6], [2, 6, 8], [3, 11, 14]])
np.linalg.matrix_rank(A)


Out[16]:
2

좌표

벡터의 성분, 즉 좌표(coordinate)는 표준 기저 벡터들에 대한 해당 벡터의 투영(projection)으로 볼 수 있다.


In [17]:
e1 = np.array([1, 0])
e2 = np.array([0, 1])
a = np.array([2, 2])

plt.annotate('', xy=e1, xytext=(0,0), arrowprops=dict(facecolor='green'))
plt.annotate('', xy=e2, xytext=(0,0), arrowprops=dict(facecolor='green'))
plt.annotate('', xy=a, xytext=(0,0), arrowprops=dict(facecolor='gray'))

plt.plot(0, 0, 'ro', ms=10)
plt.plot(a[0], a[1], 'ro', ms=10)

plt.text(1.05, 1.35, "$a$", fontdict={"size": 18})
plt.text(-0.2, 0.5, "$e_1$", fontdict={"size": 18})
plt.text(0.5, -0.2, "$e_2$", fontdict={"size": 18})

plt.xticks(np.arange(-2, 4))
plt.yticks(np.arange(-1, 4))
plt.xlim(-1.5, 3.5)
plt.ylim(-0.5, 3)
plt.show()


좌표 변환

새로운 기저 벡터를에 대해 벡터 투영을 계산하는 것을 좌표 변환(coordinate transform)이라고 한다.

좌표 변환은 새로운 기저 벡터로 이루어진 변환 행렬(transform matrix) $A$ 와의 내적으로 계산한다.

$$ Aa' = a $$$$ a' = A^{-1}a $$

예를 들어, 기존의 기저 벡터가

$$ e_1 = \begin{bmatrix}1 \\ 0\end{bmatrix} ,\;\; e_2 = \begin{bmatrix}0 \\ 1\end{bmatrix} \;\; $$

이면 벡터 $a$는 사실

$$ a = \begin{bmatrix}2 \\ 2\end{bmatrix} = 2 \begin{bmatrix}1 \\ 0\end{bmatrix} + 2 \begin{bmatrix}0 \\ 1 \end{bmatrix} = 2 e_1 + 2 e_2 $$

새로운 기저 벡터가

$$ g_1 = \begin{bmatrix} \dfrac{1}{\sqrt{2}} \\ \dfrac{1}{\sqrt{2}} \end{bmatrix} ,\;\; g_2 = \begin{bmatrix} -\dfrac{1}{\sqrt{2}} \\ \dfrac{1}{\sqrt{2}} \end{bmatrix} ,\;\; $$

이면 벡터 $a$의 좌표는 다음과 같이 바뀐다.

$$ a = \begin{bmatrix}2 \\ 2\end{bmatrix} \;\;\;\; \rightarrow \;\;\;\; a' = A^{-1}a = \begin{bmatrix} e'_1 & e'_2 \end{bmatrix} a = \begin{bmatrix} \dfrac{1}{\sqrt{2}} & -\dfrac{1}{\sqrt{2}} \\ \dfrac{1}{\sqrt{2}} & \dfrac{1}{\sqrt{2}} \end{bmatrix}^{-1} \begin{bmatrix}2 \\ 2\end{bmatrix} = \begin{bmatrix} \dfrac{1}{\sqrt{2}} & \dfrac{1}{\sqrt{2}} \\ -\dfrac{1}{\sqrt{2}} & \dfrac{1}{\sqrt{2}} \end{bmatrix} \begin{bmatrix}2 \\ 2\end{bmatrix} = \begin{bmatrix}2\sqrt{2}\\0\end{bmatrix} $$

In [18]:
e1 = np.array([1, 0])
e2 = np.array([0, 1])
a = np.array([2, 2])
g1 = np.array([1, 1])/np.sqrt(2)
g2 = np.array([-1, 1])/np.sqrt(2)

plt.annotate('', xy=e1, xytext=(0,0), arrowprops=dict(facecolor='green'))
plt.annotate('', xy=e2, xytext=(0,0), arrowprops=dict(facecolor='green'))
plt.annotate('', xy=g1, xytext=(0,0), arrowprops=dict(facecolor='red'))
plt.annotate('', xy=g2, xytext=(0,0), arrowprops=dict(facecolor='red'))
plt.annotate('', xy=a, xytext=(0,0), arrowprops=dict(facecolor='gray', alpha=0.5))

plt.plot(0, 0, 'ro', ms=10)
plt.plot(a[0], a[1], 'ro', ms=10)

plt.text(1.05, 1.35, "$a$", fontdict={"size": 18})
plt.text(-0.2, 0.5, "$e_1$", fontdict={"size": 18})
plt.text(0.5, -0.2, "$e_2$", fontdict={"size": 18})
plt.text(0.2, 0.5, "$g_1$", fontdict={"size": 18})
plt.text(-0.6, 0.2, "$g_2$", fontdict={"size": 18})

plt.xticks(np.arange(-2, 4))
plt.yticks(np.arange(-1, 4))
plt.xlim(-1.5, 3.5)
plt.ylim(-0.5, 3)
plt.show()



In [19]:
A = np.vstack([g1, g2]).T
A


Out[19]:
array([[ 0.70710678, -0.70710678],
       [ 0.70710678,  0.70710678]])

In [20]:
Ainv = np.linalg.inv(A)
Ainv


Out[20]:
array([[ 0.70710678,  0.70710678],
       [-0.70710678,  0.70710678]])

In [21]:
Ainv.dot(a)


Out[21]:
array([ 2.82842712,  0.        ])